package net.cz.wc.parser;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Scanner;

import net.cz.wc.dao.SQLDao;
import net.cz.wc.main.Context;
import net.cz.wc.olddto.OldLogDTO;
import net.cz.wc.olddto.OldMetricDTO;

public class GenericAccessParser implements Parser {

	SQLDao dao = null;
	
	public void parse(File file, Connection conn) throws Exception {
		
		Context.getContext().addDebugMessage("AccessParser.parse");
		
		Scanner scan = null;
		try {
			dao = new SQLDao(conn);
			OldLogDTO oldLog = saveLogHeader(file, conn);
			scan = new Scanner(file);
			int lineNumber = 0;
			
			while (scan.hasNextLine()) {
				lineNumber++;
				processLine(scan.nextLine(), oldLog);
			}
			
			Context.getContext().addDebugMessage("log file code: " + oldLog.getId() + ", " + lineNumber + " processed lines");
			
		} finally {
			if (scan != null) {
				scan.close();
			}
		}
	}
	
	private OldLogDTO saveLogHeader(File file, Connection conn) throws SQLException {		
		long logId = dao.getNextLogID();
		
		OldLogDTO oldLog = new OldLogDTO();
		oldLog.setId(logId);
		oldLog.setDescr("");
		oldLog.setLoadTime(new java.util.Date());
		oldLog.setFileName(file.getName());
		oldLog.setFileType("ACCESS");
		oldLog.setStampTime(0);
		
		dao.saveLog(oldLog);
		
		return oldLog;
	}
	
	/**
	 * Process an access log line with the format %h %l %u %t "%r" %s %b %D
	 * This parser generates 3 metric types for every line in the log:
	 * resptime: response time in miliseconds, corresponds with %D in the log.
	 * sentbytes: number of bytes sent by the http request, corresponds with the %b in the log.
	 * httpcode: HTTP Status code of the request, corresponds with th %s in the log.
	 * 
	 * Every metric is stored with the following format:
	 * URL:<request_url>:<metric_type> where:
	 * request_url: the URL invoked by the request, it's a 'clean' URL, it means that all characters
	 * after ? are no included neither the ? sign.
	 * @param line the line in the log file.
	 * @param oldLog DTO with the header stored in the saveLogHeader method.
	 */
	private void processLine(String line, OldLogDTO oldLog) throws SQLException {
		String[] tokens = line.split(" ");
		
		String ip = tokens[0];
		
		String date = tokens[3].substring(1, tokens[3].length());
		
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MMM/yyyy:kk:mm:ss");
		java.util.Date dateValue = null;
		try {
			dateValue = sdf.parse(date);
		} catch (ParseException ppee) {
			ppee.printStackTrace();
			dateValue = Calendar.getInstance().getTime();
			dateValue.setTime(0);
		}
		
		String url = tokens[6];
		
		if (url.indexOf('?') > 0) {
			url = url.substring(0, url.indexOf('?'));
		}
		
		String respTime = tokens[tokens.length - 1];
		
		String sentBytes = tokens[tokens.length - 2];
		
		long sentBytesValue = -1;
		try {
			if (!"-".equals(sentBytes)) {
				sentBytesValue = Long.parseLong(sentBytes);
			} else {
				sentBytesValue = 0;
			}
		} catch (NumberFormatException nnffee) {
			nnffee.printStackTrace();
		}
		
		long respTimeValue;
		
		try {
			respTimeValue = Long.valueOf(respTime);
		} catch (NumberFormatException nnee) {
			respTimeValue = -1;
		}
		
		java.util.Date startTime = new java.util.Date(dateValue.getTime() - respTimeValue);
		
		String respTimeMetricName = "URL:" + url + ":resptime";
		
		OldMetricDTO metricDto = new OldMetricDTO();
		metricDto.setIdLog(oldLog.getId());
		metricDto.setMetricName(respTimeMetricName);
		metricDto.setMetricSequence(0);
		metricDto.setMetricValue(respTimeValue);
		metricDto.setMetricStart(startTime);
		metricDto.setMetricTime(dateValue);
		
		dao.saveMetric(metricDto);
		
		String sentBytestMetricName = "URL:" + url + ":sentbytes";
		metricDto.setMetricName(sentBytestMetricName);
		metricDto.setMetricValue(sentBytesValue);
		dao.saveMetric(metricDto);
		
		String statusCode = tokens[tokens.length - 3];
		
		long httpResponseCodeValue;
		try {
			httpResponseCodeValue = Long.parseLong(statusCode);
		} catch (NumberFormatException nne) {
			httpResponseCodeValue = -1;
		}
		
		String httpResponseCodeMetricName = "URL:" + url + ":httpcode";
		metricDto.setMetricName(httpResponseCodeMetricName);
		metricDto.setMetricValue(httpResponseCodeValue);
		dao.saveMetric(metricDto);
		
		String ipResptimeMetricName = "IP:" + ip + ":resptime";
		metricDto.setMetricName(ipResptimeMetricName);
		metricDto.setMetricValue(respTimeValue);
		dao.saveMetric(metricDto);
		
		String ipSentBytesMetricName = "IP:" + ip + ":sentbytes";
		metricDto.setMetricName(ipSentBytesMetricName);
		metricDto.setMetricValue(sentBytesValue);
		dao.saveMetric(metricDto);
		
		String ipHttpCodeMetricName = "IP:" + ip + ":httpcode";
		metricDto.setMetricName(ipHttpCodeMetricName);
		metricDto.setMetricValue(httpResponseCodeValue);
		dao.saveMetric(metricDto);
	}
}
